﻿using ObjFileLoader.Data.Elements;
using ObjFileLoader.Data.VertexData;
using ObjFileLoader.Loaders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Navigation;
using System.Windows.Shapes;
using tetris_data;

namespace tetris3d_wpf
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        bool started = false;
        bool paused = false;

        GameData data = new GameData();

        private GeometryModel3D[,] cubes = new GeometryModel3D[20, 10];
        private Ellipse[,] previews = new Ellipse[4, 4];
        MaterialGroup hideMaterial = new MaterialGroup();

        public MainWindow()
        {
            InitializeComponent();
            data.Removing = () =>
            {
                Dispatcher.Invoke(() =>
                {
                    sound.Source = new Uri("media\\2.mp3", UriKind.Relative);
                    sound.Play();
                });
            };

            var brush = new SolidColorBrush(Colors.Green);
            brush.Opacity = 0.5;
            var basic = new DiffuseMaterial(brush);


            hideMaterial.Children.Add(basic);

            ImageBrush image = new ImageBrush(new BitmapImage(new Uri("Model\\Smiley face.png", UriKind.Relative)));
            image.AlignmentX = AlignmentX.Center;
            var front = new DiffuseMaterial(image);

            hideMaterial.Children.Add(front);

        }


        protected void Render()
        {
            var datas = data.BoardData;

            for (int row = 0; row < 20; row++)
            {
                for (int col = 0; col < 10; col++)
                {
                    bool show = datas[row, col].Visable;
                    if (!show)
                    {
                        HideCube(row, col);
                    }
                }
            }

            if (data.Current == null) return;
            var arr = data.Current.Data;

            for (int row = 0; row < arr.GetLength(0); row++)
            {
                for (var col = 0; col < arr.GetLength(1); col++)
                {
                    if (arr[row, col])
                    {
                        ShowMovingCube(data.Current.Top + row, data.Current.Left + col);
                    }

                }
            }
        }

        void HideCube(int row, int col)
        {
            Dispatcher.Invoke(() =>
            {
                var cube = cubes[row, col];
                cube.Material = hideMaterial;
            });
        }

        void ShowMovingCube(int row, int col)
        {
            Dispatcher.Invoke(() =>
            {
                var cube = cubes[row, col];
                var group = new MaterialGroup();
                var hightlight = new SpecularMaterial(new SolidColorBrush(Color.FromRgb(0xFF, 0xFF, 0xFF)), 45);
                var c = data.Current.Color;

                var basic = new DiffuseMaterial(new SolidColorBrush(Color.FromRgb(c.R, c.G, c.B)));

                group.Children.Add(basic);
                //group.Children.Add(hightlight);
                cube.Material = group;
            });
        }
        public void Start()
        {
            sound.Source = new Uri("media\\ding.wav", UriKind.Relative);
            sound.Play();
            started = true;
            data.RandomShape();
            Render();

            AutoDown();

        }
        private void AutoDown()
        {
            Render();

            Task.Run(() =>
            {
                data.MoveDown();
                Thread.Sleep(data.Ticks);
                if (!data.IsFull() && !paused)
                    AutoDown();
            });
        }

        public void Stop()
        {
            started = false;
        }

        public void Pause()
        {
            if (started)
            {
                paused = !paused;
            }
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            for (int row = 0; row < 4; row++)
            {
                for (int col = 0; col < 4; col++)
                {
                    Ellipse cube = new Ellipse();
                    cube.Width = 22;
                    cube.Height = 22;
                    cube.HorizontalAlignment = HorizontalAlignment.Left;
                    cube.VerticalAlignment = VerticalAlignment.Top;

                    cube.Visibility = Visibility.Collapsed;
                    var m = cube.Margin;
                    cube.Margin = new Thickness(m.Left + col * 25 + 3, m.Top + row * 25 + 3, m.Right, m.Bottom);
                    previews[row, col] = cube;
                    next.Children.Add(cube);
                }
            }

            ObjLoaderFactory factory = new ObjLoaderFactory();

            var loader = factory.Create();
            var r = loader.Load(@"Model\sphere.obj");
            MeshGeometry3D mesh = new MeshGeometry3D();
            foreach (var v in r.Vertices)
            {
                mesh.Positions.Add(new Point3D(v.X, v.Y, v.Z));
            }

            foreach (var f in r.Groups[0].Faces)
            {
                for (var i = 0; i < f.Count; i++)
                {
                    mesh.TriangleIndices.Add(f[i].VertexIndex - 1);
                    if (f[i].TextureIndex != 0)
                    {
                        var t = r.Textures[f[i].TextureIndex - 1];
                        mesh.TextureCoordinates.Add(new Point(t.X, t.Y));
                    }
                    if (f[i].NormalIndex != 0)
                    {
                        var v = r.Normals[f[i].NormalIndex - 1];
                        mesh.Normals.Add(new Vector3D(v.X, v.Y, v.Z));
                    }
                }
            }

            for (int row = 0; row < 20; row++)
            {
                for (int col = 0; col < 10; col++)
                {
                    GeometryModel3D geometry = new GeometryModel3D();
                    geometry.Geometry = mesh;

                    geometry.Material = hideMaterial;
                    var tg = new Transform3DGroup();
                    var trans = new TranslateTransform3D();
                    trans.OffsetX = col - 5;
                    trans.OffsetY = row + 0.2;
                    var trans1 = new ScaleTransform3D();
                    trans1.ScaleX = 0.8;
                    trans1.ScaleY = 0.8;
                    trans1.ScaleZ = 0.8;
                    tg.Children.Add(trans1);
                    tg.Children.Add(trans);
                    geometry.Transform = tg;
                    cubes[19 - row, col] = geometry;
                    modelGroup.Children.Add(geometry);

                }
            }
        }

        private void ProcessKey(Key key)
        {
            sound.Source = new Uri("Media\\1.mp3", UriKind.Relative);
            sound.Play();

            if (key == Key.Left) { data.MoveLeft(); }
            if (key == Key.Right) { data.MoveRight(); }
            if (key == Key.End) { data.Drop(); }
            if (key == Key.Up) { data.ChangeDirection(); }
            if (key == Key.Down) { data.MoveQuickly(); }
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            ProcessKey(e.Key);
        }


        private void Button_Click(object sender, RoutedEventArgs e)
        {
            scoreText.Text = "0";
            rowsText.Text = "0";
            levelText.Text = "0";
            Start();
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            Stop();
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            backLight.Direction = new Vector3D(backLight.Direction.X, e.NewValue, backLight.Direction.Z);
        }

        private void Slider_ValueChanged_1(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            frontLignt.Direction = new Vector3D(frontLignt.Direction.X, e.NewValue, frontLignt.Direction.Z);

        }

        private void Slider_ValueChanged_2(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            camera.Position = new Point3D(e.NewValue, camera.Position.Y, camera.Position.Z);
        }
    }
}
